/* ----------------------------------------------------------------------
*
* Copyright (C) 2024 XiaoFei. All rights reserved.
*
* @file:        XiaoFei_Vector.c
* @author:      XiaoFei
* @Date:        26-October-2024
* @Revision:    V1
* @Project:     XiaoFei DSP Library
*
* -------------------------------------------------------------------- */

#include "XiaoFei_Vector.h"
#include "stdlib.h"

/* 
* @function: 	My_FastSqrt
* @parameter:	[in] x					 	A pointer to the argument of a Square root.
* @return:		The Square root of x.
*/
static double My_FastSqrt(double x)
{
	double mi;
	mi = 1;
	if(x==0) return 0;
	if(x<0.5){
	    while(x<0.1) { x*=10;  mi*=0.316228; }
		while(x<0.5) { x*=2;   mi*=0.707107; }
	}
	if(x>2){
		while(x>10)  { x/=10;  mi*=3.162278; }
		while(x>2)   { x/=2;   mi*=1.41421;  }
	}
	return mi*(0.07246-x*(x*(x*(x*(x*(x*(x*(0.1659*x-1.5238)+5.9278)-12.7419)+16.5698)-13.4677)+6.9649)-2.8225));
}

/* 
* @function: 	My_FastExp
* @parameter:	[in] x					 	A pointer to the argument of a Exponential functions.
* @return:		The Exponential value of x.
*/
static double My_FastExp(double x)
{
	double mi;
	mi = 1;
	if((x>20)||(x<-20)) return 0;
	if(x>2){
		while(x>5)	{   x-=5;		mi*=My_EXP_5;	}
		while(x>2)	{	x-=2;		mi*=My_EXP_2;	}		
	}
	if(x<-2){
		while(x<-5)	{	x+=5;		mi/=My_EXP_5;	}
		while(x<-2)	{	x+=2;		mi/=My_EXP_2;	}		
	}
	return (1+x*(1+x*(0.5+x*(0.1667+x*(0.0417+x*(0.0083+x*(0.0014+x*(0.00022009+x*0.000026952))))))))*mi;
}

/* 
* @function: 	My_FastLog
* @parameter:	[in] x					 	A pointer to the argument of a Logarithmic function.
* @return:		The Logarithmic value of x.
*/
static double My_FastLog(double x)
{
	double mi;
	mi = 0;
	if(x<=0)	return 0;
	if(x<0.5){
		while(x<0.1)	{	x*=10;	mi-=My_LOG_10;	}
		while(x<0.5)	{	x*=2;	mi-=My_LOG_2;	}
	}
	if(x>2){
		while(x>10)     {	x/=10;	mi+=My_LOG_10;	}
		while(x>2)      {	x/=2;	mi+=My_LOG_2;	}
	}							
	return mi+0+1/(1/(x-1)+1/(2.0+1/(3/(x-1)+1/(1.0+1/(5/(x-1)+1/(2.0/3+1/(7/(x-1))))))));
}

/*
* @function: 	My_VectorCreate
* @parameter:	[in] 	size				The first address of the input vector.
* @return:		The vector memory applied to storage vectors.
*/
Vector_TypeDef My_VectorCreate(unsigned int size, double* data)
{
	Vector_TypeDef Vec;
	Vec.Size = size;
	Vec.Val = (double*)malloc(Vec.Size*sizeof(double));
	for(unsigned int i=0;i<size;i++)
		Vec.Val[i]=data[i];
	return Vec;
}

/*
* @function: 	My_VectorFree
* @parameter:	[in] 	*input			The first address of the input vector.
* @return:		None.
*/
void My_VectorFree(Vector_TypeDef* input)
{
	free(input->Val);
}

/* 
* @function: 	My_VectorAbs
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*output			The first address of the output vector based on vector absolutions.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorAbs(Vector_TypeDef* input, Vector_TypeDef* output)
{
	output->Val = (double*)malloc(input->Size*sizeof(double));
	for(int i=0;i<input->Size;i++)
		if(input->Val[i]>=0)
			output->Val[i]=input->Val[i];
		else
			output->Val[i]=-input->Val[i];
	output->Size = input->Size;
	return Success;
}

/* 
* @function: 	My_VectorAdd
* @parameter:	[in] 	*inputa			The first address of the input vector.
* @parameter:	[in] 	*inputb			The first address of another input vector.
* @parameter:	[out]	*output			The first address of the output vector based on vector additions.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorAdd(Vector_TypeDef* inputa, Vector_TypeDef* inputb, Vector_TypeDef* output)
{
	output->Val = (double*)malloc(inputa->Size*sizeof(double));
	if(inputa->Size!=inputb->Size) return Error;
	for(int i=0;i<inputa->Size;i++)
		output->Val[i] = inputa->Val[i] + inputb->Val[i];
	output->Size = inputa->Size;
	return Success;
}

/* 
* @function: 	My_VectorSub
* @parameter:	[in] 	*inputa			The first address of the input vector.
* @parameter:	[in] 	*inputb			The first address of another input vector.
* @parameter:	[out]	*output			The first address of the output vector based on vector subtraction.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorSub(Vector_TypeDef* inputa, Vector_TypeDef* inputb, Vector_TypeDef* output)
{
	output->Val=(double*)malloc(inputa->Size*sizeof(double));
	if(inputa->Size!=inputb->Size) return Error;
	for(int i=0;i<inputa->Size;i++)
		output->Val[i]=inputa->Val[i]-inputb->Val[i];
	output->Size=inputa->Size;
	return Success;
}

/* 
* @function: 	My_VectorDotprod
* @parameter:	[in] 	*inputa			The first address of the input vector.
* @parameter:	[in] 	*inputb			The first address of another input vector.
* @parameter:	[out]	output			The result of the dot product of the vector.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorDotprod(Vector_TypeDef* inputa, Vector_TypeDef* inputb, double* output)
{
	*output=0;
	if(inputa->Size!=inputb->Size) return Error;
	for(int i=0;i<inputa->Size;i++)
		*output*=inputa->Val[i]*inputb->Val[i];
	return Success;
}

/* 
* @function: 	My_VectorMul
* @parameter:	[in] 	*inputa			The first address of the input vector.
* @parameter:	[in] 	*inputb			The first address of another input vector.
* @parameter:	[out]	*output			The first address of the output vector based on vector multiplication.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorMul(Vector_TypeDef* inputa, Vector_TypeDef* inputb, Vector_TypeDef* output)
{
	output->Val = (double*)malloc(inputa->Size*sizeof(double));
	if(inputa->Size!=inputb->Size) return Error;
	for(int i=0;i<inputa->Size;i++)
		output->Val[i] = inputa->Val[i] * inputb->Val[i];
	output->Size = inputa->Size;
	return Success;
}

/* 
* @function: 	My_VectorNeg
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*output			The first address of the output vector based on vector negates.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorNeg(Vector_TypeDef* input, Vector_TypeDef* output)
{
	output->Val = (double*)malloc(input->Size*sizeof(double));
	for(int i=0;i<input->Size;i++)
			output->Val[i] = -input->Val[i];
	output->Size = input->Size;
	return Success;
}

/* 
* @function: 	My_VectorScale
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[in] 	a				The scale of the multiplication operation.
* @parameter:	[out]	*output			The first address of the output vector based on vector Scale.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorScale(Vector_TypeDef* input, double a, Vector_TypeDef* output)
{
	output->Val = (double*)malloc(input->Size*sizeof(double));
	for(int i=0;i<input->Size;i++)
			output->Val[i] = a*input->Val[i];
	output->Size = input->Size;
	return Success;
}

/*
* @function: 	My_VectorMax
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[in] 	*max			The address where the largest value is saved.
* @parameter:	[out]	*address		The address where the largest value in the vector.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorMax(Vector_TypeDef* input, double* max, unsigned int* address)
{
	*max = input->Val[0];
	*address = 0;
	for(int i=0;i<input->Size;i++)
		if(input->Val[i] > (*max)) {
			*max = input->Val[i];
				*address = i;
		}
	return Success;
}

/*
* @function: 	My_VectorMin
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[in] 	*min			The address where the smallest value is saved.
* @parameter:	[out]	*address		The address where the smallest value in the vector.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorMin(Vector_TypeDef* input, double* min, unsigned int* address)
{
	*min = input->Val[0];
	*address = 0;
	for(int i=0;i<input->Size;i++)
		if(input->Val[i] < (*min)) {
			*min = input->Val[i];
				*address = i;
		}
	return Success;
}

/*
* @function: 	My_VectorAcc
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*acc			The address where the accumulate value is saved.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorAcc(Vector_TypeDef* input, double* acc)
{
	*acc = 0;
	for(int i=0;i<input->Size;i++)
		*acc += input->Val[i];
	return Success;
}

/*
* @function: 	My_VectorMean
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*mean			The address where the mean value is saved.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorMean(Vector_TypeDef* input, double* mean)
{
	*mean = 0;
	for(int i=0;i<input->Size;i++)
		*mean += input->Val[i]/input->Size;
	return Success;
}

/*
* @function: 	My_VectorPower
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*pawer			The address where the pawer value is saved.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorPower(Vector_TypeDef* input, double* power)
{
	*power = 0;
	for(int i=0;i<input->Size;i++)
		*power += input->Val[i]*input->Val[i];
	return Success;
}

/*
* @function: 	My_VectorMeanSquare
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*meansqu		The address where the mean square value is saved.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorMeanSquare(Vector_TypeDef* input, double* meansquare)
{
	*meansquare = 0;
	for(int i=0;i<input->Size;i++)
		*meansquare += input->Val[i]*input->Val[i]/input->Size;
	return Success;
}

/*
* @function: 	My_VectorRms
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*rms			The address where the root mean square value is saved.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorRms(Vector_TypeDef* input, double* rms)
{
	static double aa;
	aa = 0;
	for(int i=0;i<input->Size;i++)
		aa += input->Val[i]*input->Val[i]/input->Size;
	*rms = My_FastSqrt(aa);
	return Success;
}

/*
* @function: 	My_VectorVar
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*var			The address where the variance value is saved.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorVar(Vector_TypeDef* input, double* var)
{
	double mean;
	*var = 0;
	if(My_VectorMean(input,&mean)==Error)
		return Error;
	for(int i=0;i<input->Size;i++)
		*var += (input->Val[i]-mean)*(input->Val[i]-mean)/(input->Size-1);
	return Success;
}

/*
* @function: 	My_VectorStd
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*std			The address where the standard deviation value is saved.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorStd(Vector_TypeDef* input, double* std)
{
	double var;
	if(My_VectorVar(input,&var)==Error)
		return Error;
	*std = My_FastSqrt(var);
	return Success;
}

/*
* @function: 	My_VectorConv
* @parameter:	[in] 	*inputa			The first address of the input vector.
* @parameter:	[in] 	*inputb			The first address of another input vector.
* @parameter:	[out]	*output			The first address of the output vector based on vector convolution.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorConv(Vector_TypeDef* inputa, Vector_TypeDef* inputb, Vector_TypeDef* output)
{
	output->Val = (double*)malloc( (inputa->Size+inputb->Size-1) * sizeof(double));
	if(inputa->Size==0||inputb->Size==0)
		return Error;
	output->Size = inputa->Size+inputb->Size-1;
	for(int i=0;i<inputa->Size;i++)
		for(int j=0;j<inputb->Size;j++)
			output->Val[i+j] += inputa->Val[i]*inputb->Val[j];
	return Success;
}

/*
* @function: 	My_VectorLse
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*lse			The address where the LogSumExp value is saved.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_VectorLse(Vector_TypeDef* input, double* lse)
{
	double max,min;
	unsigned int address;
	double sum;
	if(My_VectorMax(input,&max,&address)==Error)
		return Error;
	if(My_VectorMin(input,&min,&address)==Error)
		return Error;
	if(max>20 || min<-20)
		return Error;
	sum = 0;
	for(int i=0;i<input->Size;i++)
		sum += My_FastExp(input->Val[i]-(max-min)/2);
	*lse = (max-min)/2 + My_FastLog(sum);
	return Success;
}

/*
* @function: 	My_Swap
* @parameter:	[in] 	*a					The first number that needs to be swapped positions.
* @parameter:	[out]	*b					Another number that needs to be swapped positions.
*/
static void My_Swap(double *a, double *b)
{
    double c;
    c = *a;
    *a = *b;
    *b = c;
}

/*
* @function: 	My_BubbleSort
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*output			The first address of sorted vector.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_BubbleSort(Vector_TypeDef* input, Vector_TypeDef* output)
{
    output->Val=(double*)malloc(input->Size*sizeof(double));
    output->Size = input->Size;
	for(int i=0;i<input->Size;i++)
	    output->Val[i] = input->Val[i];
	for(int i=0;i<output->Size-1;i++)
		for(int j=0; j<output->Size-1-i;j++)
		    if(output->Val[j]>output->Val[j+1])
			    My_Swap(&output->Val[j],&output->Val[j+1]);
	return Success;
}

/*
* @function: 	My_SelectionSort
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*output			The first address of sorted vector.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_SelectionSort(Vector_TypeDef* input, Vector_TypeDef* output)
{
	output->Val=(double*)malloc(input->Size*sizeof(double));
	output->Size=input->Size;
	for(int i=0;i<input->Size;i++)
		output->Val[i]=input->Val[i];
	for(int i=0;i<output->Size-1;i++)
    {
		int min=i;
		for(int j=i+1;j<output->Size;j++)
		    if (output->Val[j]<output->Val[min]) 
		        min=j;
		if(min!=i)
			My_Swap(&output->Val[min],&output->Val[i]);
	}
	return Success;
}

/*
* @function: 	My_InsertionSort
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*output			The first address of sorted vector.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_InsertionSort(Vector_TypeDef* input, Vector_TypeDef* output)
{
	output->Val=(double*)malloc(input->Size*sizeof(double));
	output->Size=input->Size;
	for(int i=0;i<input->Size;i++)
		output->Val[i]=input->Val[i];
	for (int i=1;i<output->Size;i++)
	{
		double temp=output->Val[i];
		int j=i;
		while((j>0)&&(output->Val[j-1]>temp))
		{
            output->Val[j]=output->Val[j-1];
            j--;
		}
		output->Val[j]=temp;
	}
	return Success;
}

/*
* @function: 	My_ShellSort
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*output			The first address of sorted vector.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_ShellSort(Vector_TypeDef* input, Vector_TypeDef* output)
{
	output->Val=(double*)malloc(input->Size*sizeof(double));
	output->Size=input->Size;
	for(int i=0;i<input->Size;i++)
		output->Val[i]=input->Val[i];
	for (int gap=output->Size/2; gap>0; gap/=2) 
	{
		for (int i=gap;i<output->Size;i++) 
		{
			double temp=output->Val[i];
			int j=i;
			while (j>=gap && output->Val[j-gap]>temp) {
				output->Val[j]=output->Val[j-gap];
				j-=gap;
			}
			output->Val[j]=temp;
		}
	}
	return Success;
}

/*
* @function: 	My_QuickSortRecursive
* @parameter:	[in] 	*arr				The first address of the input vector.
* @parameter:	[in] 	start				The start address.
* @parameter:	[in] 	end					The end address.
*/
static void My_QuickSortRecursive(double *arr, int start, int end) {
    if(start>=end)
        return;
    int left=start;
    int right=end-1;
    while (left<right) {
        while(left<right&&arr[left]<arr[end])  
		    left++;
        while(left<right&&arr[right]>=arr[end])  
		    right--;
        My_Swap(&arr[left],&arr[right]);
    }
    if (arr[left]>=arr[end])   
	    My_Swap(&arr[left],&arr[end]);
    else  
	    left++;
    My_QuickSortRecursive(arr,start,left-1);
    My_QuickSortRecursive(arr,left+1,end);
}

/*
* @function: 	My_QuickSort
* @parameter:	[in] 	*input			The first address of the input vector.
* @parameter:	[out]	*output			The first address of sorted vector.
* @return:		Successes or failures of the results of the calculations.
*/
ResStatus_TypeDef My_QuickSort(Vector_TypeDef* input, Vector_TypeDef* output)
{
	output->Val=(double*)malloc(input->Size*sizeof(double));
	output->Size=input->Size;
	for(int i=0;i<input->Size;i++)
		output->Val[i]=input->Val[i];
	My_QuickSortRecursive(output->Val,0,output->Size-1);
	return Success;
}


